package ch.idsia.ai.agents.ai;

import ch.idsia.ai.agents.Agent;
import ch.idsia.mario.engine.sprites.Mario;
import ch.idsia.mario.environments.Environment;

public class OurAgent implements Agent {

	private String name;
	private boolean[] action;
	private boolean[] actionB;
	private boolean[] actionC;
    int trueJumpCounter = 0;
    int trueSpeedCounter =0;
	
	public OurAgent() {
		setName("OurAgent");
		reset();
	}
	
	public void reset() {
		action = new boolean[Environment.numberOfButtons];
		actionB = new boolean[Environment.numberOfButtons];
		actionC = new boolean[Environment.numberOfButtons];
		action[Mario.KEY_RIGHT] = true;
		actionB[Mario.KEY_RIGHT] = true;
		actionC[Mario.KEY_RIGHT] = false;
		trueJumpCounter = 0;
		trueSpeedCounter = 0;
	}

	public boolean[] getAction(Environment observation) {
        assert(observation != null);
		boolean[] jump = getJumpAction(observation);
		boolean[] enemy = getEnemyAction(observation);
		boolean[] power = getPowerAction(observation);
		
		
		if (jump[Mario.KEY_JUMP]) {
			action = jump;
			return action;
		}
		if (enemy[Mario.KEY_JUMP]) {
			actionB = enemy;
			return actionB;
		}
		if (power[Mario.KEY_RIGHT]) {
			actionC = power;
			return actionC;
		}
		
		
		 return action;
	}
	
	private boolean[] getJumpAction(Environment observation) {
		byte[][] levelScene = observation.getLevelSceneObservation();
		boolean[] jumpAction = action;
		//check if there is a gap
		boolean isGap = checkForGap(levelScene);
		//check if there is a block
		boolean isBlock = checkForHitBlock(levelScene);
				if (levelScene[11][13] != 0 || levelScene[11][12] != 0 || isGap || isBlock)
		        {
		            if (observation.mayMarioJump() || ( !observation.isMarioOnGround() && action[Mario.KEY_JUMP]))
		            {
		            	jumpAction[Mario.KEY_JUMP] = true;
		            }
		            ++trueJumpCounter;
		        }
		        else
		        {
		        	jumpAction[Mario.KEY_JUMP] = false;
		            trueJumpCounter = 0;
		        }
		        
		        if (trueJumpCounter > 20)
		        {
		            trueJumpCounter = 0;
		            jumpAction[Mario.KEY_JUMP] = false;
		        }
		        
		        jumpAction[Mario.KEY_SPEED] = isGap;
		        return jumpAction;
	}
	
	private boolean[] getEnemyAction(Environment observation) {
		byte[][] levelScene = observation.getLevelSceneObservation();
		byte[][] enemyScene = observation.getEnemiesObservation();
		boolean[] enemyAction = actionB;
				//check if there are enemies
		boolean isEnemies = checkEnemies(enemyScene);
					if (levelScene[11][13] != 0 || levelScene[11][12] != 0 || isEnemies)
				        {
				            if (observation.mayMarioJump() || ( !observation.isMarioOnGround() && action[Mario.KEY_JUMP]))
				            {
				                enemyAction[Mario.KEY_JUMP] = true;
				                enemyAction[Mario.KEY_SPEED] = true;
				            }
				            ++trueJumpCounter;
				        }
				        else
				        {
				        	enemyAction[Mario.KEY_JUMP] = false;
				        	enemyAction[Mario.KEY_SPEED] = false;
				            trueJumpCounter = 0;
				        }
				        
				        if (trueJumpCounter > 20)
				        {
				            trueJumpCounter = 0;
				            enemyAction[Mario.KEY_JUMP] = false;
				            enemyAction[Mario.KEY_SPEED] = false;
				        }
				       
				        return enemyAction;
	}
	
	private boolean[] getPowerAction(Environment observation) {
		byte[][] levelScene = observation.getLevelSceneObservation();
		byte[][] enemyScene = observation.getEnemiesObservation();
		boolean[] powerAction = actionC;
				//check if there are enemies
		boolean isPower = checkForPower(enemyScene);
					if (levelScene[11][13] != 0 || levelScene[11][12] != 0 || isPower)
				        {
				            if (observation.mayMarioJump() || ( !observation.isMarioOnGround() && action[Mario.KEY_RIGHT]))
				            {
				                //powerAction[Mario.KEY_JUMP] = true;
				            	powerAction[Mario.KEY_RIGHT] = false;
				            	System.out.println("Power");
				            }
				            //++trueJumpCounter;
				        }
				        else
				        {
				        	powerAction[Mario.KEY_RIGHT] = false;
				            trueJumpCounter = 0;
				        }
				        
				        if (trueJumpCounter > 20)
				        {
				            trueJumpCounter = 0;
				            powerAction[Mario.KEY_RIGHT] = false;
				        }
				       
				        return powerAction;
	}
	
	private void visualizeLevel(byte[][] levelScene) {
		String formater = "";
		System.out.println("------------------------------------------------------------------------------------------------");
		for (int i = 0; i < levelScene.length; i++) {
			System.out.print(i + ": ");
			for (int j = 0; j < levelScene[i].length; j++) {
				formater = " ";
				System.out.print('|');
				if (levelScene[i][j] < 0) {
					if (levelScene[i][j] < -9) {
						formater = "";
					}
					else {
						formater = " ";
					}
				}
				else if (levelScene[i][j] > 9) {
					formater = " ";
				}
				System.out.print(formater + levelScene[i][j]);
			}
			System.out.print('\n');
		}
	}

	public AGENT_TYPE getType() {
		return Agent.AGENT_TYPE.AI;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	private boolean checkForGap(byte[][] levelScene) {
		for (int x = 9; x < 13; ++x)
        {
            boolean f = true;
            for(int y = 12; y < 22; ++y)
            {
                if  (levelScene[y][x] != 0)
                    f = false;
            }
            if (f && levelScene[12][13] != 0 || f && levelScene[12][14] != 0
            		|| f && levelScene[12][15] != 0) {
            	return true;
        }
        }
        return false;
        
	}
	
	private boolean checkForEnemy(byte[][] enemyScene, int e) {
		for (int x = 9; x < 20; ++x)
        {
            boolean f = true;
            for(int y = 8; y < 14; ++y)
            {
                if  (enemyScene[y][x] == e)
                    f = true;
            }
            if (f && enemyScene[11][12] == e ||
            	f && enemyScene[11][13] == e ||
            	f && enemyScene[11][14] == e ||
            	f && enemyScene[10][12] == e ||
            	f && enemyScene[10][13] == e ||
            	f && enemyScene[10][14] == e ||
            	f && enemyScene[12][12] == e ||
            	f && enemyScene[12][13] == e ||
            	f && enemyScene[12][14] == e)
                return true;
        }
        return false;
        
	}
	
	private boolean checkForPower(byte[][] enemyScene) {
		for (int x = 9; x < 13; ++x)
        {
            boolean f = true;
            for(int y = 4; y < 14; ++y)
            {
                if  (enemyScene[y][x] == 14 || enemyScene[y][x] == 15)
                    f = true;
            }
            if (f && enemyScene[7][8] == 14 || f && enemyScene[7][8] == 15 ||
            	f && enemyScene[7][9] == 14 || f && enemyScene[7][9] == 15 ||
            	f && enemyScene[7][10] == 14 || f && enemyScene[7][10] == 15 ||
            	f && enemyScene[8][8] == 14 || f && enemyScene[8][8] == 15 ||
            	f && enemyScene[8][9] == 14 || f && enemyScene[8][9] == 15 ||
            	f && enemyScene[8][10] == 14 || f && enemyScene[8][10] == 15 ||
            	f && enemyScene[9][8] == 14 || f && enemyScene[9][8] == 15 ||
            	f && enemyScene[9][9] == 14 || f && enemyScene[9][9] == 15 ||
            	f && enemyScene[9][10] == 14 ||f && enemyScene[9][10] == 15)
            	//System.out.println("Power");
                return true;
        }
        return false;
        
	}
	
	private boolean checkEnemies(byte[][] enemyScene) {
		return (checkForEnemy(enemyScene, 2) || checkForEnemy(enemyScene, 3)
				|| checkForEnemy(enemyScene, 4) || checkForEnemy(enemyScene, 5)
				|| checkForEnemy(enemyScene, 6) || checkForEnemy(enemyScene, 7)
				|| checkForEnemy(enemyScene, 8) || checkForEnemy(enemyScene, 9)
				|| checkForEnemy(enemyScene, 10) || checkForEnemy(enemyScene, 12));
	}

	

	private boolean checkForHitBlock(byte[][] levelScene) {
		for (int x = 9; x < 13; ++x) {
			boolean f = true;
			for (int y = 0; y < 11; ++y) {
				if (levelScene[y][x] == 21 || levelScene[y][x] == 16)
					f = true;
			}
			if (f && levelScene[8][11] == 21 || f && levelScene[8][11] == 16)
				return true;
		}
		return false;
	}
	
	
}